package account

import (
	"context"
	"encoding/json"
	"fmt"
	"strconv"
	"time"
	"user/internal/biz"
	"user/internal/model"
	"user/internal/svc"
	"user/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type LoginLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic {
	return &LoginLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *LoginLogic) Login(req *types.LoginReq) (resp *types.LoginResp, err error) {
	// todo: add your logic here and delete this line
	userModel := model.NewCustomerEntityModel(l.svcCtx.Mysql)
	user, err := userModel.FindOneByUsernameAndPassword(l.ctx, req.Username, req.Password)
	if err != nil {
		l.Logger.Error("用户登录查询失败:", err)
		return nil, biz.DBError
	}
	if user == nil {
		return nil, biz.LoginError
	}

	token, err := biz.GenerateToken(user.Id, l.svcCtx.Config.Auth.AccessSecret, l.svcCtx.Config.Auth.AccessExpire)
	if err != nil {
		l.Logger.Error("用户登录生成token失败:", err)
		return nil, biz.TokenError
	}

	expire := l.svcCtx.Config.Auth.AccessExpire
	err = l.svcCtx.Redis.SetexCtx(l.ctx, "token:"+token, strconv.FormatInt(user.Id, 10), int(expire))
	if err != nil {
		l.Logger.Error("redis设置token失败:", err)
		return nil, biz.RedisError
	}

	resp = &types.LoginResp{
		Token: token,
	}

	// 记录日志
	go func() {
		logData := map[string]any{
			"usernamne": user.Username,
			"ip":        l.ctx.Value("ip"),
			"userId":    user.Id,
			"time":      time.Now().Format("2006-01-01 15:04:05"),
			"type":      "login",
			"msg":       "登录成功",
		}

		bytes, _ := json.Marshal(logData)
		// 上下文一般也是写超时的上下文
		err := l.svcCtx.KafkaPushCli.PushWithKey(context.Background(), fmt.Sprint("log_%d", user.Id), string(bytes))
		if err != nil {
			l.Logger.Error("写入失败:", err)
		}
	}()

	return
}
